using NatCamU.Core;
using OpenCVForUnity;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Util = NatCamU.Core.Utilities.Utilities;

/// <summary>
/// 该类中包含了所有用于Argar平台的工具类
/// </summary>
namespace Argar.Camera
{
    public class AdvancedNatcamToMatHelper : MonoBehaviour
    {
        [Header("Parameters")]
        public Facing facing = Facing.Rear;
        public ResolutionPreset previewResolution = ResolutionPreset.HD;
        public ResolutionPreset photoResolution = ResolutionPreset.HD;
        public FrameratePreset framerate = FrameratePreset.LowestFramerate;
        /// <summary>
        /// The downscale ratio.
        /// </summary>
        public float downscaleRatio = 2;

        [Header("Debugging")]
        public Switch verbose;

        [Header("Events")]
        public UnityEvent OnInitedEvent;
        public UnityEvent OnUpdateEvent;
        public UnityEvent OnDisposedEvent;

        /// <summary>
        /// 用于保存PreviewMatrix的引用
        /// 这样当需要使用时就可以直接使用
        /// </summary>
        private Mat matrix;

        /// <summary>
        /// The rgba downscale mat.
        /// </summary>
        private Mat downScaleRgbaMat;

        /// <summary>
        /// 释放所有被 AdvancedNatCamToMatHelper 使用的资源
        /// </summary>
        /// <remarks>
        /// 当你不再使用 AdvancedNatCamToMatHelper 时调用该方法, 
        /// 它会使AdvancedNatCamToMatHelper进入不可用状态。
        /// 调用Dispose后, 你必须释放掉所有包含 AdvancedNatCamToMatHelper
        /// 的引用, 这样垃圾回收机制才能清除掉被占用的资源
        /// </remarks>
        private void Dispose()
        {
            //Release NatCam
            NatCam.Release();
            //Dispose the matrix if it isn't null
            if (matrix != null)
            {
                matrix.Dispose();
                matrix = null;
            }

            if (downScaleRgbaMat != null)
            {
                downScaleRgbaMat.Dispose();
                downScaleRgbaMat = null;
            }

            //Invoke the OnDisposedEvent
            if (OnDisposedEvent != null) OnDisposedEvent.Invoke();
        }

        /// <summary>
        /// 用于初始化的私有函数
        /// </summary>
        private void _Init()
        {
            // Set verbose mode
            NatCam.Verbose = verbose;
            // Set the active camera
            NatCam.Camera = facing == Facing.Front ? DeviceCamera.FrontCamera : DeviceCamera.RearCamera;
            // Null checking
            if (!NatCam.Camera)
            {
                // Log
                Util.LogError("Active camera is null. Consider changing the facing of the camera");
                return;
            }
            // Set the camera's preview resolution
            NatCam.Camera.SetPreviewResolution(previewResolution);
            // Set the camera's photo resolution
            NatCam.Camera.SetPhotoResolution(photoResolution);
            // Set the camera's framerate
            NatCam.Camera.SetFramerate(framerate);
            // Play
            NatCam.Play();
            // Register callback for when the preview starts 
            // NatCam.Preview的赋值必须是在OnStart中！！！
            // 在NatCam.OnStart()中并不保证GetMat()一定不为空！
            NatCam.OnStart += OnStart;
            // Register for preview updates
            // 与GetMat有关的数据应该在这里赋值！！
            NatCam.OnFrame += OnFrame;
        }

        #region --NatCam Callbacks--

        /// <summary>
        /// 覆盖了NatCamBehaviour中的OnStart
        /// 所以不再进行preview.text = NatCam.Preview的操作
        /// </summary>
        public void OnStart()
        {
            // Invoke initialization event
            if (OnInitedEvent != null) OnInitedEvent.Invoke();
        }

        /// <summary>
        /// 每次NatCam刷新帧时被调用
        /// NatCam的图像刷新与Update不同步
        /// </summary>
        public void OnFrame()
        {
            // Invoke update event
            if (OnUpdateEvent != null) OnUpdateEvent.Invoke();
        }

        #endregion

        #region --Client API--

        /// <summary>
        /// 想使用MatHelper, 必须先使用Init()方法初始化NatCam
        /// </summary>
        public void Init()
        {
            // If playing, ignore
            if (NatCam.IsPlaying) return;
            // Create initialization event if null
            OnInitedEvent = OnInitedEvent ?? new UnityEvent();
            // Create disposed event if null
            OnDisposedEvent = OnDisposedEvent ?? new UnityEvent();
            // Start NatCam
            _Init();
        }

        /// <summary>
        /// 获取矩阵的对外接口
        /// </summary>
        /// <returns>
        /// 8UC4的RGBA矩阵, 可能为null
        /// </returns>
        public Mat GetMat()
        {
            NatCam.PreviewMatrix(ref matrix);
            return matrix;
        }

        /// <summary>
        /// Gets the mat that downscaled the original mat.
        /// if downscaleRatio <= 1 , return originalMat. 
        /// </summary>
        /// <returns>The downscale mat.</returns>
        /// <param name="originalMat">Original mat.</param>
        public Mat GetDownScaleMat(Mat originalMat)
        {
            if (downscaleRatio <= 1)
                return originalMat;

            if (downScaleRgbaMat == null)
            {
                downScaleRgbaMat = new Mat();
            }

            Imgproc.resize(originalMat, downScaleRgbaMat, new Size(), 1.0 / downscaleRatio, 1.0 / downscaleRatio, Imgproc.INTER_LINEAR);

            return downScaleRgbaMat;
        }


        /// <summary>
        /// Gets the device camera.
        /// </summary>
        /// <returns>The device camera.</returns>
        public DeviceCamera GetDeviceCamera()
        {
            return NatCam.Camera;
        }

        public void Play()
        {
            if (!NatCam.IsPlaying) NatCam.Play();
        }

        public void Pause()
        {
            if (NatCam.IsPlaying) NatCam.Pause();
        }

        public void Stop()
        {
            Dispose();
        }

        #endregion
    }
}


